jf_web

Plotly

Code
import numpy as np
import plotly.graph_objects as go
import plotly.io as pio

#-------------Base parameters

#Define curve parameters
period    = 50
n_samples = 100
sim_duration  = period*10
amp = 3
x = np.arange(n_samples)*np.pi/period

#Animation parameters
frame_duration = 50 #milliseconds?

#Define some groups of parameters here as dictionaries
#  This greatly clarifies later code
#  plotly takes arguments which are lists of dicts of lists of dicts... confusing
def frame_arguments(duration):
    return {
        "frame": {"duration": duration},
        "mode": "immediate",
        "redraw": True,
        "fromcurrent": True,
        "transition": {"duration": duration, "easing": "linear"},
        "uirevision": True
    }

#--------------Meat and potatoes

#Create figure object containing one trace of the desired graph type
fig = go.Figure(
        data=[go.Scatter3d(
            x = [],
            y = [],
            z = [],
            mode = "lines",
            name = "SineTest")])


#Define the layout of that figure (size, axes ranges, etc.)
fig.update_layout(
    template = "plotly_white",
    scene = dict(
            xaxis=dict(range=[0,2*np.pi], autorange=False),
            yaxis=dict(range=[-3,3], autorange=False),
            zaxis=dict(range=[0,2*np.pi], autorange=False)))

#Now customize -- set the background to transparent to pair with theme
fig.update_layout(plot_bgcolor='rgba(0, 0, 0, 0)',paper_bgcolor='rgba(0, 0, 0, 0)')


#Define all frames within the animation
frames =  [go.Frame(data=[go.Scatter3d(
                            x=x,
                            y=amp*np.sin(x+t*np.pi/period),
                            z=x)],
                    traces=[0],
                    name=f"frame_{t}")
                    for t in range(1, sim_duration)]

#Assign said frames to the figure
fig.update(frames=frames)

#Define the protocols for updating the figure
#  Here, a button which causes the figure to loop linearly through the frame
fig.update_layout(
    updatemenus = [
        {
            "buttons": [
                {
                    "label" : "Play",
                    "method" : "animate", #Affects animation
                    "args" : [None, frame_arguments(frame_duration)]
                },
                {
                    "label" : "Pause",
                    "method" : "animate",
                    #To FutureJake: This is jank you can't just make a pause button by setting the frame duration to ten billion seconds [FIX]
                    #  To PastJake: Who's going to stop me?
                    "args" : [None, frame_arguments(1000000000)]
                }
            ],
            #Position/display arguments for the buttons
            "y" : 0.5,
            "yanchor" : "bottom",
            "xanchor" : "center",
            "type" : "buttons"
        },
        {
            "buttons": [
                {
                    "label" : "Lightmode",
                    "method" : "relayout", #Affects layout attributes
                    "args" : ["template", pio.templates["plotly_white"]]
                },
                {
                    "label" : "Darkmode",
                    "method" : "relayout", #Affects layout attributes
                    "args" : ["template", pio.templates["plotly_dark"]]
                }
            ],
            "y" : 0.4,
            "yanchor" : "top",
            "xanchor" : "center",
            "direction" : "down",
            "type" : "dropdown"
        }
    ]
)        

#Finally, render the figure
fig.show()
Code
import plotly.graph_objects as go
import numpy as np

#Curve parameters
period    = 50
n_samples = 100
sim_time  = period*10

x = np.arange(n_samples)*np.pi/period

fig = go.Figure(go.Scatter(x=x, y=np.sin(x), mode='lines', name='Testing Points'))
fig.update_layout(title='Animation Test',
                  title_x=0.5,
                  width=600, height=600, 
                  xaxis_title='time', 
                  yaxis_title='E',
                  yaxis_range=(-1.5, 1.5),
                  xaxis_range=(0,2*np.pi),
                  #defines the play button and animation settings
                  updatemenus=[dict(buttons = [dict(
                                               args = [None, {"frame": {"duration": period, 
                                                                        "redraw": False},
                                                              "fromcurrent": True, 
                                                              "transition": {"duration": 0}}],
                                               label = "Play",
                                               method = "animate")],
                                type='buttons',
                                showactive=False,
                                xanchor='right',
                                yanchor='top')])
                                          
frames= [go.Frame(data=[go.Scatter(x=x, y=np.sin(x+t*np.pi/period))]) for t in range(1, sim_time)]
fig.update(frames=frames)

fig.show()